package by.bsu.fpmi.bbtp.authentication;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;

import javax.jws.WebService;

@Aspect
public class AuthenticationAspect {

    private static final String ADMIN_SESSION_ID = "42";

    @Autowired
    private LoginController loginController;

    @Around("execution(public * by.bsu.fpmi.bbtp.controllers.*+.*(..)) && args(sessionId, ..)")
    public Object checkAuthentication(ProceedingJoinPoint pjp, String sessionId) throws Throwable {
        Class<?> controller = getControllerInterface(pjp.getTarget());
        Role[] allowedRoles = getAllowedRoles(controller);
        if (hasAccess(sessionId, allowedRoles)) {
            return pjp.proceed();
        } else {
            throw new AccessDeniedException(controller, allowedRoles);
        }
    }
    
    private boolean hasAccess(String sessionId, Role[] allowedRoles) {
        if (ADMIN_SESSION_ID.equals(sessionId)) {
            return true;
        }
        for (Role role : allowedRoles) {
            if (loginController.isAuthenticatedAs(sessionId, role)) {
                return true;
            }
        }
        return false;
    }
    
    private Class<?> getControllerInterface(Object controllerImpl) {
        for (Class<?> intf : controllerImpl.getClass().getInterfaces()) {
            if (intf.getAnnotation(WebService.class) != null) {
                return intf;
            }
        }
        throw new IllegalArgumentException(controllerImpl.getClass().getName() + " is not a web service conroller.");
    }
    
    private Role[] getAllowedRoles(Class<?> controller) {
        AllowedRoles allowedRoles = controller.getAnnotation(AllowedRoles.class);
        if (allowedRoles != null) {
            return allowedRoles.value();
        } else {
            return new Role[0];
        }
    }
}
